// src/services/dlsiteScraper.js

const axios = require('axios'); // 引入axios模块用于HTTP请求
const cheerio = require('cheerio'); // 引入cheerio用于解析HTML
const { HttpsProxyAgent } = require('https-proxy-agent'); // 引入HttpsProxyAgent模块，用于通过代理服务器发送HTTPS请求

const fs = require('fs');
const path = require('path');

/**
 * DLsiteScraper类，用于从DLsite网站上抓取产品信息。
 */
class DLsiteScraper {
    /**
     * 构造函数，初始化代理服务器URL和DLsite基本URL。
     * 
     * @param {string} [proxyUrl='http://127.0.0.1:7890'] - 代理服务器的URL
     */
    constructor(proxyUrl = 'http://127.0.0.1:7890') {
        this.baseUrl1 = 'https://www.dlsite.com/home/work/=/product_id/';
        this.baseUrl2 = 'https://www.dlsite.com/maniax-touch/product/info/ajax?product_id=';
        this.proxyAgent = new HttpsProxyAgent(proxyUrl); // 使用代理服务器创建代理请求对象
        this.coverPath = './covers/';
    }


    // 创建一个处理重定向的自定义函数
    async fetchWithLocale(url, proxyAgent) {
        try {
            // 第一次请求，禁用自动重定向
            const response = await axios.get(url, {
                httpsAgent: proxyAgent,
                proxy: false, // 不使用系统代理
                maxRedirects: 0 // 禁用自动重定向
            });

            return response;  // 如果没有重定向，直接返回响应

        } catch (error) {
            // 判断是否是重定向错误
            if (error.response && (error.response.status === 301 || error.response.status === 302)) {
                // 捕获重定向后的URL
                let redirectedUrl = error.response.headers.location;
                console.log('Redirecting to:', redirectedUrl);

                // 检查并添加 `?locale=zh_CN`
                if (!redirectedUrl.includes('locale=zh_CN')) {
                    redirectedUrl += '?locale=zh_CN';
                    console.log('Modified URL with locale:', redirectedUrl);
                }

                // 再次发起请求，并返回最终响应
                return await axios.get(redirectedUrl, {
                    httpsAgent: proxyAgent,
                    proxy: false
                });
            } else {
                // 其他错误处理
                throw error;
            }
        }
    }

    /**
     * 抓取指定产品代码的产品信息。
     * 
     * @param {string} code - 产品代码（例如RJ, BJ, VJ编号）
     * @returns {Promise<Object|null>} - 返回包含产品信息的对象，抓取失败时返回null
     */
    async scrapeProduct(code) {
        const url1 = this.getProductUrl(code)[0]; // 获取产品的完整URL
        const url2 = this.getProductUrl(code)[1];

        try {

            const [response1, response2] = await Promise.all([
                this.fetchWithLocale(url1, this.proxyAgent), // 使用自定义函数处理url1的重定向逻辑
                axios.get(url2, {
                    httpsAgent: this.proxyAgent, // 使用代理服务器发送请求
                    proxy: false // 确保axios不会使用系统代理设置
                })
            ]);

            // 加载两个页面的内容以便进行解析
            const $ = cheerio.load(response1.data);
            const json1 = response2.data[code];

            this.getCover(json1, code);

            // 返回抓取到的产品信息
            return {
                code,                               // 产品代码
                title: this.getTitle($),            // 产品标题
                circle: this.getCircle($),          // 制作团队（或社团）名称
                releaseDate: this.getReleaseDate($),// 发售日期
                series: this.getSeries($),          // 系列名
                va: this.getVoiceActor($),          // 声优列表
                ageCategory: this.getAgeCategory($),// 年龄指定
                workType: this.getWorkType(json1),  // 作品类型 
                tags: this.getTags($),              // 标签列表
                price: this.getPrice(json1),        // 价格
                sales: this.getSales(json1),        // 销量
                rating: this.getRating(json1)       // 评价
            };
        } catch (error) {
            console.error(`Error scraping ${code}:`, error.message); // 错误处理
            return null;
        }
    }

    /**
     * 根据产品代码生成产品的DLsite页面URL。
     * 
     * @param {string} code - 产品代码
     * @returns {string} - 产品页面的完整URL
     */
    getProductUrl(code) {
        return [`${this.baseUrl1}${code}.html/?locale=zh_CN`, `${this.baseUrl2}${code}`]; // 返回对应产品的URL
    }

    /**
     * 从页面中提取产品的标题。
     * 
     * @param {Object} $ - cheerio对象，解析HTML内容
     * @returns {string} - 产品标题
     */
    getTitle($) {
        return $('h1[id="work_name"]').text().trim(); // 获取产品名称并去除多余空格
    }

    getTitleFromJSON(json1) {
        let title1 = json1.work_name;
        let title2 = json1.work_name_masked;
        if (title1.length != 0) {
            return title1;
        } else if (title2.length != 0) {
            return title2;
        } else {
            return '';
        }
    }

    /**
     * 从页面中提取制作团队（社团）的信息。
     * 
     * @param {Object} $ - cheerio对象
     * @returns {Object} - 返回包含社团ID和名称的对象
     */
    getCircle($) {
        const circleElement = $('span[class="maker_name"]').children('a');
        const circleUrl = circleElement.attr('href');
        const circleName = circleElement.text();
        let circle = (circleUrl && circleName)
            ? { id: parseInt(circleUrl.substr(-10, 5)), name: circleName }
            : {};
        return circle;
    }

    /**
     * 从页面中提取产品的发售日期。
     * 
     * @param {Object} $ - cheerio对象
     * @returns {string} - 发售日期，格式为YYYY-MM-DD
     */
    getReleaseDate($) {
        const workOutline = $('#work_outline');
        let release = workOutline.children('tbody').children('tr').children('th')
            .filter(function () {
                return $(this).text() === '贩卖日';
            }).parent().children('td').text().replace(/[^0-9]/ig, '');
        release = (release.length >= 8)
            ? `${release.slice(0, 4)}-${release.slice(4, 6)}-${release.slice(6, 8)}`
            : '';
        return release;
    }

    /**
     * 从页面中提取系列信息。
     * 
     * @param {Object} $ - cheerio对象
     * @returns {Object|null} - 返回系列对象或null
     */
    getSeries($) {
        const workOutline = $('#work_outline');
        const seriesElement = workOutline.children('tbody').children('tr').children('th')
            .filter(function () {
                return $(this).text() === '系列名';
            }).parent().children('td').children('a');
        if (seriesElement.length) {
            const seriesUrl = seriesElement.attr('href');
            if (seriesUrl.match(/SRI(\d{10})/)) {
                let series = {
                    id: parseInt(seriesUrl.match(/SRI(\d{10})/)[1]),
                    name: seriesElement.text()
                };
                return series;
            }
        }
        return null;
    }

    /**
     * 从页面中提取产品的声优列表。
     * 
     * @param {Object} $ - cheerio对象
     * @returns {Array<string>} - 包含声优名称的数组
     */
    getVoiceActor($) {
        const workOutline = $('#work_outline');
        let va = [];
        workOutline.children('tbody').children('tr').children('th')
            .filter(function () {
                return $(this).text() === '声优';
            }).parent().children('td').children('a').each(function () {
                const vaName = $(this).text().trim();
                va.push(vaName);
            });
        return va;
    }

    /**
     * 从页面中提取产品的年龄指定。
     * 
     * @param {Object} $ - cheerio对象
     * @returns {string} - 年龄指定，R18、R-15或全年龄 
     */
    getAgeCategory($) {
        const workOutline = $('#work_outline');
        let ageCategory = workOutline.children('tbody').children('tr').children('th')
            .filter(function () {
                return $(this).text() === '年龄指定';
            }).parent().children('td').find('span:first').text();
        return ageCategory;
    }


    getWorkType(json1) {
        switch (json1.work_type) {
            case 'SOU':
                return '音声・ASMR';
            case 'DNV':
                return '电子小说';
            case 'ADV':
                return '冒险';
            case 'PZL':
                return '益智';
            case 'SLN':
                return '模拟';
            case 'RPG':
                return '角色扮演';
            case 'ACN':
                return '动作';
            case 'ETC':
                return '其他游戏';
            case 'MNG':
                return '漫画';
            case 'MOV':
                return '视频';
            case 'ICG':
                return 'CG・插画';
            case 'MUS':
                return '音乐';
            case 'TOL':
                return '工具/装饰';
            case 'AMT':
                return '声音素材';
            case 'IMT':
                return '图片素材';
            case 'QIZ':
                return '解谜';
            case 'STG':
                return '射击';
            case 'NRE':
                return '小说';
            case 'ET3':
                return '其他';
            case 'TBL':
                return '桌游';
            case 'TYP':
                return '打字';
            case 'VCM':
                return '音声漫画';
            case 'SCM':
                return '剧画';
            case 'WBT':
                return 'Webtoon';
            case 'KSV':
                return '官能小说';
            default:
                return '未知';
        }
    }

    /**
     * 从页面中提取产品的标签列表。
     * 
     * @param {Object} $ - cheerio对象
     * @returns {Array<Object>} - 包含标签ID和名称的对象数组
     */
    getTags($) {
        const workOutline = $('#work_outline');
        let tags = [];
        workOutline.children('tbody').children('tr').children('th')
            .filter(function () {
                return $(this).text() === '分类';
            }).parent().children('td').children('div').children('a').each(function () {
                const tagUrl = $(this).attr('href');
                const tagName = $(this).text();
                if (tagUrl.match(/genre\/(\d{3})/)) {
                    tags.push({
                        id: parseInt(tagUrl.match(/genre\/(\d{3})/)[1]),
                        name: tagName
                    });
                }
            });
        return tags;
    }

    getPrice(json1) {
        if (json1.official_price_str != null) {
            return json1.official_price_str;
        } else if (json1.official_price != null) {
            return json1.official_price;
        } else if (json1.price_str != null) {
            return json1.price_str;
        } else {
            return json1.price;
        }
    }

    getSales(json1) {
        if (json1.dl_count_total == 0 || json1.dl_count_total == null) {
            return {
                total_sale: json1.dl_count,
                favorites: json1.wishlist_count,
                sale_detail: JSON.stringify(json1.dl_count_items)
            }
        } else {
            return {
                total_sale: json1.dl_count_total,
                favorites: json1.wishlist_count,
                sale_detail: JSON.stringify(json1.dl_count_items)
            }
        }
    }

    getRating(json1) {
        return {
            average_rating: json1.rate_average_2dp,
            rating_count: json1.rate_count,
            score_detail: JSON.stringify(json1.rate_count_detail)
        }
    }

    async getCover(json1, code) {
        const filename = code + '.jpg';
        const filePath = path.join(this.coverPath, filename);

        // 确保文件夹存在
        if (!fs.existsSync(this.coverPath)) {
            fs.mkdirSync(this.coverPath);
        }

        // 检查文件是否已存在
        if (fs.existsSync(filePath)) {
            console.log(`File already exists: ${filePath}, skipping download.`);
            return;
        }

        try {
            // 使用 axios 下载图片
            const response = await axios({
                method: 'get',
                url: 'https:' + json1.work_image,
                responseType: 'stream', // 设置响应类型为流
                httpsAgent: this.proxyAgent, // 设置代理
            });

            // 创建写入流保存图片
            const writer = fs.createWriteStream(filePath);
            response.data.pipe(writer);

            writer.on('finish', () => {
                console.log(`Image downloaded and saved as ${filePath}`);
            });

            writer.on('error', (err) => {
                console.error('Error writing the file:', err.message);
            });
        } catch (error) {
            console.error('Error downloading the image:', error.message);
        }
    }
}

module.exports = DLsiteScraper; // 导出DLsiteScraper类
